#include "RouteUtil.h"
#include "log.h"

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <net/route.h>
#include <set>


namespace Media{


set<string> netcardName = {"eth0", "wlan0", "wlan1", "default"};


bool RouteUtil::AddRouteItem(const RouteItem &item, int isDefGateway, int metric)
{
	LOG_PrintInfo("AddRouteItem::item.dest_ip:%s  item.ethName:%s  item.mask:%s  item.nexthop:%s, metric=%d\n", 
	            item.dest_ip.c_str(), item.ethName.c_str(), item.mask.c_str(), item.nexthop.c_str(), metric);
    int sockfd;
    struct rtentry rt;//创建结构体变量
    memset(&rt, 0, sizeof(struct rtentry));
    
    //创建套接字
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1)
    {
        perror("socket creation failed\n");
        return false;
    }
    //设置网关，又名下一跳：转到下个路由的路由地址
    struct sockaddr_in *sockinfo = (struct sockaddr_in *)&rt.rt_gateway;
    sockinfo->sin_family = AF_INET;
    sockinfo->sin_addr.s_addr = inet_addr(item.nexthop.c_str());
 
    //设置目的地址
    sockinfo = (struct sockaddr_in *)&rt.rt_dst;
    sockinfo->sin_family = AF_INET;
    sockinfo->sin_addr.s_addr = inet_addr(item.dest_ip.c_str());
 
    //设置子网掩码
    sockinfo = (struct sockaddr_in *)&rt.rt_genmask;
    sockinfo->sin_family = AF_INET;
    sockinfo->sin_addr.s_addr = inet_addr(item.mask.c_str());
 
    //设置网卡设备名
    if(isDefGateway == 0)
    {
        rt.rt_flags = RTF_UP;
    }
    else
    {
        rt.rt_flags = RTF_UP | RTF_GATEWAY;
    }
    
    rt.rt_dev = (char *)item.ethName.c_str();

	rt.rt_metric = metric;
    //ioctl接口进行路由属性设置
    if (ioctl(sockfd, SIOCADDRT, &rt) < 0)
    {
        perror("ioctl:");
        close(sockfd);
        return false;
    }
 
    return true;
}


/*
描述：
    删除路由项
参数：
    item：路由对象
返回值：
    成功：true 失败：false
*/
bool RouteUtil::DelRouteItem(const RouteItem &item)
{
    LOG_PrintInfo("DelRouteItem::item.dest_ip:%s  item.ethName:%s  item.mask:%s	item.nexthop:%s  item.nexthop:%d\n", item.dest_ip.c_str(), item.ethName.c_str(), item.mask.c_str(), item.nexthop.c_str(), item.metric);
    int fd;
    struct sockaddr_in _sin;
    struct sockaddr_in *sin = &_sin;
    struct rtentry rt;
 
    fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0)
    {
        perror("create fd of socket error:");
        return false;
    }
    // 要删除的网关信息，网关信息可以不填充，有ip 子网掩码即可删除路由
    memset(&rt, 0, sizeof(struct rtentry));
    memset(sin, 0, sizeof(struct sockaddr_in));
    sin->sin_family = AF_INET;
    sin->sin_port = 0;
    if (inet_aton(item.nexthop.c_str(), &sin->sin_addr) < 0)
    {
        perror("gateWay inet_aton error:");
        close(fd);
        return false;
    }
    memcpy(&rt.rt_gateway, sin, sizeof(struct sockaddr_in));
    //要删除的ip信息
    ((struct sockaddr_in *)&rt.rt_dst)->sin_family = AF_INET;
    if (inet_aton(item.dest_ip.c_str(), &((struct sockaddr_in *)&rt.rt_dst)->sin_addr) < 0)
    {
        perror("dest addr inet_aton error:");
        close(fd);
        return false;
    }
    //要删除的子网掩码
    ((struct sockaddr_in *)&rt.rt_genmask)->sin_family = AF_INET;
    if (inet_aton(item.mask.c_str(), &((struct sockaddr_in *)&rt.rt_genmask)->sin_addr) < 0)
    {
        perror("mask inet_aton error:");
        close(fd);
        return false;
    }
    //网卡设备名
    rt.rt_dev = (char *)item.ethName.c_str();
    rt.rt_flags = RTF_UP | RTF_GATEWAY;
    if(item.metric == 0){
        rt.rt_metric = item.metric;
    }else{
        rt.rt_metric = WLAN0ROUTEMETRIC;
    }

    if (ioctl(fd, SIOCDELRT, &rt) < 0)
    {
        perror("ioctl SIOCADDRT error : ");
        close(fd);
        return false;
    }
 
    close(fd);
 
    return true;
}


/*
描述：
    获得路由表
参数：
    routeTable:保存路由表的容器
返回值：
    成功：true 失败：false
*/
bool RouteUtil::GetRouteTabel(const string target, vector<RouteItem> &routeTable)
{
	if(netcardName.find(target) == netcardName.end())
	{
		LOG_PrintError("cat not support params target:%s\n", target.c_str());
		return false;
	}
	// ubuntu
	vector<RouteItem> defaultTable;
	vector<RouteItem> ethTable;
	vector<RouteItem> wlan0Table;
	vector<RouteItem> wlan1Table;
    FILE *fp;
    char devname[64];
    unsigned long d, g, m;
    int r = 0;
    int flgs, ref, use, metric, mtu, win, ir;
    uint8_t gate[4] = {0};
    uint8_t ip[4] = {0};
    uint8_t mask[4] = {0};
    std::string gateway;
    uint8_t ip_str[15] = {0};
    uint8_t mask_str[15] = {0};
    uint8_t gate_str[15] = {0};
    RouteItem item;
 
    fp = fopen("/proc/net/route", "r");

     // 检查文件是否成功打开
    if (fp == NULL) {
        LOG_PrintError("cannot fopen /proc/net/route \n");
        return false;
    }
    /* Skip the first line. */
    r = fscanf(fp, "%*[^\n]\n");
    if (r < 0)
    {
        /* Empty line, read error, or EOF. Yes, if routing table
         * is completely empty, /proc/net/route has no header.
         */
        fclose(fp);
        return false;
    }
 
    // ubuntu
    while (1)
    {
        r = fscanf(fp, "%63s%lx%lx%X%d%d%d%lx%d%d%d\n",
                   devname, &d, &g, &flgs, &ref, &use, &metric, &m,
                   &mtu, &win, &ir);
 
        if (r != 11)
        {
            if ((r < 0) && feof(fp))
            { /* EOF with no (nonspace) chars read. */
 
                break;
            }
        }
        //        printf("%63s %lx %lx %X %d %d %d %lx %d %d %d\n", devname, d, g, flgs, ref, use, metric, m, mtu, win, ir);
        // RTF_UP表示该路由可用，RTF_GATEWAY表示该路由为一个网关，组合在一起就是3，表示一个可用的网关
        if (true)
        {
            memcpy(ip, &d, 4);
            memcpy(mask, &m, 4);
            memcpy(gate, &g, 4);
            sprintf((char *)gate_str, "%d.%d.%d.%d", gate[0], gate[1], gate[2], gate[3]);
            sprintf((char *)ip_str, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
            sprintf((char *)mask_str, "%d.%d.%d.%d", mask[0], mask[1], mask[2], mask[3]);
            item.ethName = devname;
            item.dest_ip = (char *)ip_str;
            item.mask = (char *)mask_str;
            item.nexthop = (char *)gate_str;
            item.metric = metric;
            
			
			// LOG_PrintInfo("item.dest_ip:%s  item.ethName:%s  item.mask:%s	item.nexthop:%s\n", item.dest_ip.c_str(), item.ethName.c_str(), item.mask.c_str(), item.nexthop.c_str());
			if(item.dest_ip ==  "0.0.0.0"){
				defaultTable.push_back(item);
			}else{
				if(item.ethName == "wlan0"){
					wlan0Table.push_back(item);
				}else if(item.ethName == "eth0"){
					ethTable.push_back(item);
				}else if(item.ethName == "wlan1"){
					wlan1Table.push_back(item);
				}
			}
        }
    }

    bool iRet = false;
    
	if(target == "default"){
	    if(!defaultTable.empty())
	    {
		    routeTable = defaultTable;
		    iRet = true;
		}
	}else if(target == "eth0"){
	    if(!ethTable.empty())
	    {
		    routeTable = ethTable;
		    iRet = true;
		}
	}else if(target == "wlan0"){
	    if(!wlan0Table.empty())
	    {
		    routeTable = wlan0Table;
		    iRet = true;
		}
	}else if(target == "wlan1"){
	    if(!wlan1Table.empty())
	    {
		    routeTable = wlan1Table;
		    iRet = true;
		}
	}

#if 0
	std::vector<RouteItem>::iterator iter;
	for (iter = routeTable.begin(); iter != routeTable.end(); iter++)
    {
        std::cout << iter->ethName << "  " << iter->dest_ip << "  " << iter->mask << "  " << iter->nexthop << std::endl;
    }
#endif
    fclose(fp);
	return iRet;
}

}

